# Image Processing tools for processing the image files

import cv2
import numpy as np

def readGreyscaleImage(filename):
    """Reads an image file as greyscale and returns it."""

    return cv2.imread(filename, cv2.CV_LOAD_IMAGE_GRAYSCALE)

def writeGreyscaleImage(img, filename):
    """Writes a greyscale image to a file."""

    cv2.imwrite(filename, img)

def binarize(im_gray):
    """Returns the binary form of a greyscale image."""

    (thresh, im_bw) = cv2.threshold(im_gray, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    return im_bw

def resizeTo100x100(im):
    """Resizes the image to 100x100 and returns the resulting image."""
    
    return cv2.resize(im, (100, 100))

def convertToZeroTen(img):
    """Returns a zero-ten form of the image with each pixel having a value either 0 or 10.

    An assigned value of 0 means that in the binarized image, that pixel was white.
    An assigned value of 10 means that in the binarized image, that pixel was black.

    """

    img_bw = binarize(img)
    height, width = img.shape
    new_img = np.zeros((height, width), np.uint8)
    for i in range(height):
        for j in range(width):
            if img_bw[i, j] == 255:
                new_img[i, j] = 0
            else:
                new_img[i, j] = 10
    return new_img

def scale(img, factor):
    """Scales the value of each pixel in a greyscale image by factor and returns the resulting image."""

    height, width = img.shape
    new_img = np.zeros((height, width), np.uint8)
    for i in range(height):
        for j in range(width):
            new_img[i, j] = img[i, j] * factor
    return new_img

def createGradientHelper(img_zt, i, j, factor):
    """Helper function for createGradient()."""

    height, width = img_zt.shape
    new_factor = factor - 1
    if new_factor > 0:
        if i != 0:
            if img_zt[i - 1, j] != 10:
                img_zt = createGradientHelper(img_zt, i - 1, j, new_factor)
            if j != 0 and img_zt[i - 1, j - 1] != 10:
                img_zt = createGradientHelper(img_zt, i - 1, j - 1, new_factor)
            if j != (width - 1) and img_zt[i - 1, j + 1] != 10:
                img_zt = createGradientHelper(img_zt, i - 1, j + 1, new_factor)
        if i != (height - 1):
            if img_zt[i + 1, j] != 10:
                img_zt = createGradientHelper(img_zt, i + 1, j, new_factor)
            if j != 0 and img_zt[i + 1, j - 1] != 10:
                img_zt = createGradientHelper(img_zt, i + 1, j - 1, new_factor)
            if j != (width - 1) and img_zt[i + 1, j + 1] != 10:
                img_zt = createGradientHelper(img_zt, i + 1, j + 1, new_factor)
        if j!= 0 and img_zt[i, j - 1] != 10:
            img_zt = createGradientHelper(img_zt, i, j - 1, new_factor)
        if j != (width - 1) and img_zt[i, j + 1] != 10:
            img_zt = createGradientHelper(img_zt, i, j + 1, new_factor)
    val = 2 * factor
    if img_zt[i, j] < val:
        img_zt[i, j] = val
    return img_zt

def createGradient(img_zt):
    """Creates a gradient over a zero-ten image and returns it."""

    height, width = img_zt.shape
    new_img = np.zeros((height, width), np.uint8)
    for i in range(height):
        for j in range(width):
            new_img[i, j] = img_zt[i, j]
    for i in range(height):
        for j in range(width):
            if new_img[i, j] == 10:
                new_img = createGradientHelper(new_img, i, j, 5)
    return new_img

def getBoundingBox(image):
    """Returns limits of the region of interest."""

    img = binarize(image)
    height, width = img.shape
    topLimit = -1
    bottomLimit = -1
    leftLimit = width + 1
    rightLimit = -1
    for i in range(height):
        for j in range(width):
            if img[i, j] == 0:
                if topLimit == -1:
                    topLimit = i
                if bottomLimit < i:
                    bottomLimit = i
                if rightLimit < j:
                    rightLimit = j
                if leftLimit > j:
                    leftLimit = j
    return leftLimit, rightLimit, topLimit, bottomLimit

def autoCrop(img):
    """Autocrops the image and returns it."""

    left, right, top, bottom = getBoundingBox(img)
    return resizeTo100x100(img[top:bottom, left:right])